#include "multhread.h"

multhread::multhread()
{
    this->isDone =true;
}

bool multhread::setPointer(pcap_t *pointer)
{
    this->pointer = pointer;
    if(pointer)
        return true;
    else
        return false;
}

void multhread::setFlag()
{
    this->isDone = false;
}

void multhread::resetFlag()
{
    this->isDone = true;
}


int multhread::ethernetPackageHandle(const u_char *pkt_content, QString &info)
{
    ETHER_HEADER* ethernet;
    ethernet = (ETHER_HEADER*)(pkt_content); // 获取以太网头部
    u_short content_type;
    content_type = NTOHS(ethernet->_ether_type); // 获取以太网类型
    switch (content_type) {
    case 0x0800://ip
    {
        int ipPackage = 0;
        int res = ipPackageHandle(pkt_content, ipPackage); // 处理IP包
        switch (res)
        {
        case 1:
        {//icmp
            return icmpPackageHandle(pkt_content, info); // 处理ICMP包
        }
        case 6:
        {//tcp
            return tcpPackageHandle(pkt_content, info, ipPackage); // 处理TCP包
        }
        case 17:
        {//udp
            return udpPackageHandle(pkt_content, info); // 处理UDP包
        }
        default:break;
        }
        return 0;
    }
    case 0x0806://arp
    {
        info = arpPackageHandle(pkt_content); // 处理ARP包
        return 1;
    }
    default:break;
    }
    return 0;
}

int multhread::ipPackageHandle(const u_char *pkt_content, int &ipPackage)
{
    // 获取IP头部
	IP_HEADER* ip;
	ip = (IP_HEADER*)(pkt_content + 14);
    
    // 获取协议类型
	int protocol = ip->_protocol;
    
    // 获取IP头部长度
	char len = ip->_version_headerLen & 0x0f;
    
    // 计算IP包的有效载荷长度
	ipPackage = NTOHS(ip->_totalLen) - len * 4;
    
    // 返回协议类型
	return protocol;
}

int multhread::tcpPackageHandle(const u_char *pkt_content, QString &info, int ipPackage)
{
    TCP_HEADER* tcp;
    tcp = (TCP_HEADER*)(pkt_content + 34);
    u_short src = NTOHS(tcp->_sport);
    u_short des = NTOHS(tcp->_dport);
    QString proSend = "";
    QString proRecv = "";

    int type = 3;

    //获取tcp载荷长度
    int delta = (tcp->_off_res_flag >> 12) * 4;
    int tcpLoader = ipPackage - delta;

    //提取源端口，目的端口
    if (src == 443 || des == 443)
    {
        if (src == 443)
            proSend = "(https)";
        else
            proRecv = "(https)";
    }
    info += QString::number(src) + proSend + "->" + QString::number(des) + proRecv;
    //提取标志位信息
    QString flag = "";
    if (tcp->_off_res_flag & 0x20) flag += "URG,";
    if (tcp->_off_res_flag & 0x10) flag += "ACK,";
    if (tcp->_off_res_flag & 0x08) flag += "PSH,";
    if (tcp->_off_res_flag & 0x04) flag += "RST,";
    if (tcp->_off_res_flag & 0x02) flag += "SYN,";
    if (tcp->_off_res_flag & 0x01) flag += "FIN,";
    if (flag != "")
    {
        flag = flag.left(flag.length() - 1);
        info += "[" + flag + "]";
    }

    //提取窗口大小，序列号
    u_int sequence = NTOHSL(tcp->_seqNum);

    u_int ack = NTOHSL(tcp->_ackNum);

    u_short window = NTOHS(tcp->_winSize);
    
    info += "Seq=" + QString::number(sequence) + "Ack=" + QString::number(ack) + "WindowSize=" + QString::number(window)+"len="+QString::number(tcpLoader);

    return type;
}

int multhread::udpPackageHandle(const u_char *pkt_content, QString &info)
{
    UDP_HEADER* udp;
    udp = (UDP_HEADER*)(pkt_content + 34); // 获取UDP头部信息
    u_short des = NTOHS(udp->_dport); // 获取目的端口
    u_short src = NTOHS(udp->_sport); // 获取源端口
    if (des == 53 || src == 53) // 判断是否为DNS数据包
    {
        info = dnsPackageHandle(pkt_content); // 处理DNS数据包
        return 5; // 返回DNS数据包类型
    }
    else
    {
        QString res = QString::number(src) + "->" + QString::number(des); // 构建源端口到目的端口的字符串
        u_short data_len = NTOHS(udp->_len); // 获取数据长度
        res += "len=" + QString::number(data_len); // 添加数据长度到字符串
        info += res; // 将结果添加到info中
        return 4; // 返回UDP数据包类型
    }
}

int multhread::icmpPackageHandle(const u_char *pkt_content, QString &info)
{
    ICMP_HEADER* icmp;
    icmp = (ICMP_HEADER*)(pkt_content + 34); // 获取ICMP头部信息
    u_char type = icmp->_type; // 获取ICMP类型
    u_char code = icmp->_code; // 获取ICMP代码
    if (code == 0) // 如果代码为0
    {
        if (type == 8) // 如果类型为8
        {
            info += "Echo (ping) request  "; // 添加ping请求信息
        }
        else if (type == 0) // 如果类型为0
        {
            info += "Echo (ping) reply  "; // 添加ping回复信息
        }
        else if (type == 3) // 如果类型为3
        {
            info += "Networt unreachable  "; // 添加网络不可达信息
        }
    }
    u_short id = NTOHS(icmp->_identification); // 获取标识符

    char buf[1024];
    _itoa_s(id, buf, 16); // 将标识符转换为16进制字符串

    QString sId = buf;
    info += "id=0x" + sId + ",  "; // 添加标识符信息

    u_short seq = NTOHS(icmp->_seq); // 获取序列号
    info += "seq=" + QString::number(seq); // 添加序列号信息

    return 2; // 返回ICMP数据包类型
}

QString multhread::arpPackageHandle(const u_char *pkt_content)
{
    ARP_HEADER* arp;
    arp = (ARP_HEADER*)(pkt_content + 14); // 获取ARP头部信息

    u_short op = NTOHS(arp->_op_type); // 获取操作类型
    QString res = "";
    u_char* dipaddr = arp->_des_ip_addr; // 获取目的IP地址
    QString desIp = QString::number(*dipaddr) + "."
                    + QString::number(*(dipaddr + 1)) + "."
                    + QString::number(*(dipaddr + 2)) + "."
                    + QString::number(*(dipaddr + 3)); // 构建目的IP地址字符串
    u_char* sipaddr = arp->_src_ip_addr; // 获取源IP地址
    QString srcIp= QString::number(*sipaddr) + "."
                    + QString::number(*(sipaddr + 1)) + "."
                    + QString::number(*(sipaddr + 2)) + "."
                    + QString::number(*(sipaddr + 3)); // 构建源IP地址字符串

    u_char* src_eth_addr = arp->_src_ether_addr; // 获取源MAC地址
    QString srcEth = byteToString(src_eth_addr, 1) + ":"
                     + byteToString(src_eth_addr + 1, 1) + ":"
                     + byteToString(src_eth_addr + 2, 1) + ":"
                     + byteToString(src_eth_addr + 3, 1) + ":"
                     + byteToString(src_eth_addr + 4, 1) + ":"
                     + byteToString(src_eth_addr + 5, 1); // 构建源MAC地址字符串

    if (op == 1) // 如果操作类型为1（ARP请求）
    {
        res = "who has " + desIp + "? Tell " + srcIp; // 构建ARP请求信息
    }
    else if (op == 2) // 如果操作类型为2（ARP应答）
    {
        res = srcIp + " is at " + srcEth; // 构建ARP应答信息
    }
    return res; // 返回结果字符串
}

QString multhread::dnsPackageHandle(const u_char *pkt_content)
{
    DNS_HEADER* dns;
    dns = (DNS_HEADER*)(pkt_content + 14 + 20 + 8); // 获取DNS头部信息
    u_short id = NTOHS(dns->_id); // 获取DNS标识符
    u_short type = NTOHS(dns->_flag); // 获取DNS标志
    QString info = "";
    if ((type & 0xf800) == 0x0000) // 判断是否为标准查询
    {
        info = "Standard query ";
    }
    else if ((type & 0xf800) == 0x8000) // 判断是否为标准查询响应
    {
        info = "Standard query response ";
    }
    QString name = "";
    char* domain = (char*)(pkt_content + 14 + 20 + 8 + 12); // 获取域名信息
    while (*domain != 0x00) // 遍历域名信息
    {
        if (domain && (*domain) <= 64) // 判断域名长度
        {
            int length = *domain;
            domain++;
            for (int i = 0; i < length; i++) // 读取域名
            {
                name += (*domain);
                domain++;
            }
            name += ".";
        }
        else
            break;
    }
    if (name != "") // 去掉最后一个点
    {
        name = name.left(name.length() - 1);
    }
    return info + "0x" + QString::number(id, 16) + " " + name; // 返回DNS信息
}

QString multhread::byteToString(u_char *str, int size)
{
    QString res = "";
    for (int i = 0; i < size; i++)
    {
        char one = str[i] >> 4; // 获取高4位
        if (one >= 0x0A)
            one += 0x41 - 0x0A; // 转换为字母
        else one += 0x30;
        char two = str[i] & 0xF; // 获取低4位
        if (two >= 0x0A)
            two += 0x41 - 0x0A; // 转换为字母
        else two += 0x30;
        res.append(one);
        res.append(two);
    };
    return res; // 返回结果字符串
}


void multhread::run()
{
    while (1) // 无限循环
    {
        if (isDone) // 如果完成标志为真，跳出循环
            break;
        else
        {
            int ret = pcap_next_ex(pointer, &(packHeader), &(packData)); // 获取下一个数据包
            if (ret != 1) continue;  // 捕获失败，循环继续
            local_time_sec = packHeader->ts.tv_sec; // 获取本地时间（秒）
            localtime_s(&local_time, &local_time_sec); // 将时间转换为本地时间结构
            strftime(timeString, sizeof(timeString), "%H:%M:%S", &local_time); // 格式化时间字符串
            QString info = "";
            int type = ethernetPackageHandle(packData, info); // 处理以太网数据包
            if (type) // 如果数据包类型有效
            {
                DataPackage data;
                int len = packHeader->len; // 获取数据包长度
                data.setDataLength(len); // 设置数据包长度
                data.setInfo(info); // 设置数据包信息
                data.setTimeStmp(timeString); // 设置时间戳
                data.setPackageType(type); // 设置数据包类型
                data.setPointer(packData, len); // 设置数据包指针
                emit send(data); // 发送数据包信号
            }
        }
    }
}
